//TerrainWater.h
//Created 20/02/14
//Created By Daniel Bowler
//
//Represents the terrain water. 

#pragma once

//Advanced model
#include "AbstractAdvancedModel.h"

//Include terrain
#include "Terrain.h"

//How far under the water layer to draw the underwater layer. 
#define WATER_DEPTH 8.0f

//Height of the clip plane. 
#define CLIP_PLANE_HEIGHT 0.0f

//If uncommented, we render the water as a lake (can be calm
//or smooth - see the #define in TerrainWater.fx). Else, more like a river. 
//#define USE_LAKE_SHADER

//Effects used when rendering
class TerrainWaterFX;
class TileForwardTextureMapFX;

class TerrainWater : public AbstractAdvancedModel
{
	//Allow terrain to access private data
	friend class Terrain;
public:
	//Standard constructor/destrouctor
	TerrainWater();
	~TerrainWater();

	//Init the water. 
	void Init(ID3D11Device* device, 
		float width, float depth,
		XMFLOAT3 location);	

	//Update the water
	void Update(float delta);

	//Called when the screen changes size - recreate reflect/refact maps. 
	void OnResize(int w, int h);

	//Draws reflection or refaction texture. 
	void DebugDrawRefactionTexture(ID3D11DeviceContext* context);
	void DebugDrawReflectionTexture(ID3D11DeviceContext* context);

public:
	//Renders the water.
	void Render(bool isZPrePass, bool isOpaquePass, bool isShadowPass,		   //Flags telling us what pass it is. 
		VirtualCamera* playerCamera,										   //Player camera - passed from GraphicsInterface
		DirecLightShadowMapData* shadowMap,									   //Single shadow map - passed from GraphicsInterface. 
		SSAOData* ssaoMap,													   //SSAO Map.
		ID3D11ShaderResourceView* envMap,									   //Environment map. 
		ID3D11ShaderResourceView* llb,                                         //Light list buffer - gloabl set of lights. 
		ID3D11ShaderResourceView* llibO, ID3D11ShaderResourceView* llsebO,     //Opaque Tile Based Forward buffers. 
		ID3D11ShaderResourceView* llibT, ID3D11ShaderResourceView* llsebT,     //Transparant pass. 
		DirectionalLight* dLightArr, unsigned dLightCount,					   //Directional lights and light count. 
		XMFLOAT3 &hemiColDown, XMFLOAT3 &hemiColRange,						   //Hemispherical ambient lighting data.
		CXMMATRIX &view, CXMMATRIX &proj,									   //Cameras view/proj or the shadow maps view/proj depending on the pass. 
		ID3D11DeviceContext* context);										   //Context we are rendeirng through. 

	//Draws refaction
	void RenderRefaction(bool isZPrePass, bool isOpaquePass, bool isShadowPass,
		VirtualCamera* playerCamera,										 
		DirecLightShadowMapData* shadowMap,									   
		SSAOData* ssaoMap,													  
		ID3D11ShaderResourceView* envMap,									    
		ID3D11ShaderResourceView* llb,                                         
		ID3D11ShaderResourceView* llibO, ID3D11ShaderResourceView* llsebO,     
		ID3D11ShaderResourceView* llibT, ID3D11ShaderResourceView* llsebT,     
		DirectionalLight* dLightArr, unsigned dLightCount,					   
		XMFLOAT3 &hemiColDown, XMFLOAT3 &hemiColRange,						   
		CXMMATRIX &view, CXMMATRIX &proj,									    
		ID3D11DeviceContext* context, 
		std::vector<TerrainPatchData*>&patches);		    //All patches - we render just surrounding patches								   
	
	//Draws reflection
	void RenderReflection(bool isZPrePass, bool isOpaquePass, bool isShadowPass,
		VirtualCamera* playerCamera,										 
		DirecLightShadowMapData* shadowMap,									   
		SSAOData* ssaoMap,													  
		ID3D11ShaderResourceView* envMap,									    
		ID3D11ShaderResourceView* llb,                                         
		ID3D11ShaderResourceView* llibO, ID3D11ShaderResourceView* llsebO,     
		ID3D11ShaderResourceView* llibT, ID3D11ShaderResourceView* llsebT,     
		DirectionalLight* dLightArr, unsigned dLightCount,					   
		XMFLOAT3 &hemiColDown, XMFLOAT3 &hemiColRange,						   
		CXMMATRIX &view, CXMMATRIX &proj,									    
		ID3D11DeviceContext* context, 
		std::vector<TerrainPatchData*>&patches);		
private:
	//Effect used to render the water
	TerrainWaterFX* effect;

	//VB And IB of the grid
	ID3D11Buffer* vb;
	ID3D11Buffer* ib;

	//Indicies to draw
	unsigned drawCount;

	//Material 
	Material mat;

	//Normal tex transform. 
	XMFLOAT2 normTransformScale;
	XMFLOAT2 normTransformScale2;
	XMFLOAT2 normTransformTrans;
	XMFLOAT2 normTransformTrans2;

	//Matricies - pass to shader. 
	XMFLOAT4X4 normTransform;
	XMFLOAT4X4 normTransform2;

	//Normal map
	ID3D11ShaderResourceView* normalMap;

private:
	//Effect for underwater grid
	TileForwardTextureMapFX* underwaterEffect;

	//Stuff for the underwater layer. 
	ID3D11Buffer* underwaterVB;
	ID3D11Buffer* underwaterIB;

	//Underwater tex
	ID3D11ShaderResourceView* underWaterTex;

	//World matrix of underwater layer. 
	XMFLOAT4X4 underwaterWorld;

	//Texture matrix for underwater layer
	XMFLOAT4X4 underwaterTexMat;

	//Underwater material
	Material underwaterMat;

private:
	//Reflection/Refaction map
	ID3D11ShaderResourceView* reflectionMapSRV;
	ID3D11ShaderResourceView* refactionMapSRV;

	ID3D11RenderTargetView* reflectionMapRTV;
	ID3D11RenderTargetView* refactionMapRTV;

	//Also need a depth bufer for each of the two render textures
	ID3D11DepthStencilView* reflectionMapDSV;
	ID3D11DepthStencilView* refactionMapDSV;

	//Viewport for these textures
	D3D11_VIEWPORT reflectRefactViewport;

	//Size of the reflection/refaction map
	int reflectionRefactMapSizeW;
	int reflectionRefactMapSizeH;

private:
	//Create the grids IB and VB
	void CreateGrid(ID3D11Device* device, 
		float width, float depth);

	//Loads underwater stuff
	void LoadUnderWaterResources(ID3D11Device* device, 
		float width, float depth);

	//Create the reflection and refaction texture map
	void CreateReflectionMap(ID3D11Device* device);
	void CreateRefactionMap(ID3D11Device* device);

private:
	//Draw Water
	void DrawWaterLayer(bool isZPrePass, bool isOpaquePass, bool isShadowPass,		  
		VirtualCamera* playerCamera,										
		DirecLightShadowMapData* shadowMap,								
		SSAOData* ssaoMap,													  
		ID3D11ShaderResourceView* envMap,									   
		ID3D11ShaderResourceView* llb,                                       
		ID3D11ShaderResourceView* llibO, ID3D11ShaderResourceView* llsebO,  
		ID3D11ShaderResourceView* llibT, ID3D11ShaderResourceView* llsebT,     
		DirectionalLight* dLightArr, unsigned dLightCount,					   
		XMFLOAT3 &hemiColDown, XMFLOAT3 &hemiColRange,						   
		CXMMATRIX &view, CXMMATRIX &proj,									
		ID3D11DeviceContext* context);

	//Draws quad underneath water
	void DrawUnderWaterLayer(bool isZPrePass, bool isOpaquePass, bool isShadowPass,		  
		VirtualCamera* playerCamera,										
		DirecLightShadowMapData* shadowMap,								
		SSAOData* ssaoMap,													  
		ID3D11ShaderResourceView* envMap,									   
		ID3D11ShaderResourceView* llb,                                       
		ID3D11ShaderResourceView* llibO, ID3D11ShaderResourceView* llsebO,  
		ID3D11ShaderResourceView* llibT, ID3D11ShaderResourceView* llsebT,     
		DirectionalLight* dLightArr, unsigned dLightCount,					   
		XMFLOAT3 &hemiColDown, XMFLOAT3 &hemiColRange,						   
		CXMMATRIX &view, CXMMATRIX &proj,									
		ID3D11DeviceContext* context);

private:
	//Draws a single patch to the reflection map
	void RenderPatchReflection(bool isZPrePass, bool isOpaquePass, bool isShadowPass,		  
		VirtualCamera* playerCamera,										
		DirecLightShadowMapData* shadowMap,								
		SSAOData* ssaoMap,													  
		ID3D11ShaderResourceView* envMap,									   
		ID3D11ShaderResourceView* llb,                                       
		ID3D11ShaderResourceView* llibO, ID3D11ShaderResourceView* llsebO,  
		ID3D11ShaderResourceView* llibT, ID3D11ShaderResourceView* llsebT,     
		DirectionalLight* dLightArr, unsigned dLightCount,					   
		XMFLOAT3 &hemiColDown, XMFLOAT3 &hemiColRange,						   
		CXMMATRIX &view, CXMMATRIX &proj,									
		ID3D11DeviceContext* context, 
		XMFLOAT4 &clipPlane,                //Inverted Clip Plane
		TerrainPatchData* patch);			//The patch to draw
};